package com.icekrvams.billing.data

import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.lifecycle.MutableLiveData
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase
import com.icekrvams.billing.Billing
import com.icekrvams.billing.utilities.BillingUtilities
import com.icekrvams.billing.utilities.dLog
import com.icekrvams.billing.utilities.resetWith

/**
 * 从所有已拥有商品中筛选出订阅类型的商品。
 */
internal fun List<Purchase>.subPurchases(): List<Purchase> {
    return this.filter {
        it.products.any { productId ->
            DataHolder.products.allSubProducts.contains(productId)
        }
    }
}

/**
 * 从所有已拥有商品中筛选出一次性购买类型的商品。
 */
internal fun List<Purchase>.oneTimePurchases(): List<Purchase> {
    return this.filter {
        it.products.any { productId ->
            DataHolder.products.allOneTimeIapProducts.contains(productId)
        }
    }
}

/**
 * 从所有已拥有商品中筛选出可消耗类型的商品。
 */
internal fun List<Purchase>.consumablePurchases(): List<Purchase> {
    return this.filter {
        it.products.any { productId ->
            DataHolder.products.consumableIapProducts.contains(productId)
        }
    }
}

/**
 * 维护商品相关的数据信息。
 * 1.Products：客户端声明的商品 Id 信息。
 * 2.ProductDetails：根据商品 Id 查询到的商品详情信息。
 * 3.Purchase：已拥有商品的订单信息。
 */
internal object DataHolder {

    lateinit var products: Products // 客户端传入的所有商品 id。

    /**
     * 应用初始化时，读取本地存储的订阅状态和已拥有一次性内购商品。
     */
    internal fun initialize(products: Products) {
        this.products = products
        ownedProductsLiveData.value = ownedProductsFromSp
    }

    /**
     * 保存已拥有的所有的商品（包含订阅商品和一次性购买商品）。
     * 查询已购买商品完成，或者应用回到前台时，BillingSdk 重新查询已拥有商品，[purchases] 的值会得到更新。
     */
    val purchases = mutableListOf<Purchase>()

    /**
     * 重制并持久化已拥有的商品。
     */
    fun resetPurchases(purchases: List<Purchase>) {
        this.purchases.resetWith(purchases)
        persistOwnedProducts()
    }

    /**
     * 商品 id 与商品详情的映射，查询商品信息完成 [productWithProductDetails] 的值会得到更新。
     */
    val productWithProductDetails = mutableMapOf<String, ProductDetails>()

    /**
     * 保存已拥有的商品的 LiveData。
     * 由于初始化时会立即将本地保存的状态设置给 ownedProductsLiveData，所以调用 observe 方法时，回调方法会立即被调用。
     * 已拥有的商品发生变化时，回调方法也会被调用。
     * @sample
     *  Billing.ownedProductsLiveData.observe(lifecycleOwner) { ownedProducts ->
     *      if (ownedProducts.contains("product")) {
     *          // Do something when product owned.
     *      } else {
     *
     *      }
     *  }
     *
     */
    val ownedProductsLiveData = MutableLiveData<List<String>>()

    val ownedProducts: List<String> get() = ownedProductsLiveData.value ?: ownedProductsFromSp

    /**
     * 判断是否已经拥有目标商品。
     * @param product 商品 Id。
     */
    fun isProductOwned(product: String): Boolean {
        if (!(products.allSubProducts + products.allOneTimeIapProducts).contains(product)) {
            throw IllegalArgumentException("$product is not a sub product or one-time iap product")
        }
        val ownedSubProducts = ownedProductsLiveData.value ?: ownedProductsFromSp
        return ownedSubProducts.contains(product)
    }

    private const val BILLING_SHARED_PREFERENCE_NAME = "billing_shared_prefs_name"
    private const val PREF_KEY_OWNED_PRODUCTS = "pref_key_owned_products"

    /**
     * 持久化存储已拥有的订阅商品和一次性内购商品。
     */
    private fun persistOwnedProducts() {
        // 当前可用的和已经弃用的订阅项都参与检查。
        val ownedProducts = BillingUtilities.deviceOwnedProducts()
        if (ownedProductsLiveData.value != ownedProducts) {
            ownedProductsLiveData.postValue(ownedProducts)
            val ownedProductsStr = ownedProducts.joinToString()
            sharedPreference.edit {
                putString(PREF_KEY_OWNED_PRODUCTS, ownedProductsStr)
            }
            "persistOwnedProducts:$ownedProductsStr".dLog()
        }
    }

    /**
     * 获取本地之久化存储的已拥有的订阅商品。
     */
    private val ownedProductsFromSp: List<String>
        get() = sharedPreference.getString(PREF_KEY_OWNED_PRODUCTS, null)?.split(", ")
            ?: emptyList()

    /**
     * 用于持久化存储订阅状态的 SharedPreference 对象。
     * 持久化存储的作用：
     * 在应用初始化到查询订阅项完成这段时间内（可能很短），依然能够保证订阅状态是已知的，让 Billing 组件中的订阅状态随时可用。
     */
    private val sharedPreference: SharedPreferences
        get() = Billing.app.getSharedPreferences(
            BILLING_SHARED_PREFERENCE_NAME,
            Context.MODE_PRIVATE
        )
}
